Skip to content

S11-03 Vue-路由

[TOC]

API-Vue Router

概述

路由发展

  • 后端路由阶段
  • 前后端分离阶段
  • 单页面富应用(SPA)

后端路由阶段

服务端渲染:服务器直接渲染好对应的HTML页面, 返回给客户端进行展示。

服务端渲染流程

  1. 一个页面有自己对应的网址, 也就是URL。
  2. URL会发送到服务器, 服务器会通过正则对该URL进行匹配, 并且最后交给一个Controller进行处理。
  3. Controller进行各种处理, 最终生成HTML或者数据, 返回给前端。

优点:

  • 1、渲染好的页面, 不需要单独加载任何的js和css, 可以直接交给浏览器展示。
  • 2、有利于SEO的优化。

缺点:

  • 整个页面的模块由后端人员来编写和维护。
  • 前端开发人员如果要开发页面, 需要通过PHP和Java等语言来编写页面代码。
  • HTML代码和数据以及对应的逻辑会混在一起, 编写和维护困难。

前后端分离阶段

前后端分离:后端只提供API来返回数据,前端通过Ajax获取数据,并且可以通过JS将数据渲染到页面中。

优点:

  • 前后端责任的清晰,后端专注于数据上,前端专注于交互和可视化。
  • 当移动端(iOS/Android)出现后,后端不需要进行任何处理,依然使用之前的一套API。

路由模式

  • URL的hash
  • HTML5的History

URL的hash

URL的hash:也就是锚点(#), 本质上是改变window.location的href属性。我们可以通过直接赋值location.hash来改变href, 但是页面不发生刷新

优点:兼容性更好,在老版IE中都可以运行

缺点:有一个#,显得不像一个真实的路径

示例:

image-20250220151613113

HTML5的History

history接口是HTML5新增的, 它有六种模式改变URL而不刷新页面

history.pushState()(state,title?,url?),用于将一个新的历史记录条目添加到浏览器的历史记录栈中,而不会刷新页面。

history.replaceState()(state,title?,url?),用于替换当前浏览器历史记录中的条目。

history.back()(),用于让浏览器回到历史记录中的前一个页面。可理解为模拟用户点击浏览器的“后退”按钮。

history.forward()(),用于让浏览器前进到历史记录中的下一个页面。可理解为模拟用户点击浏览器的“前进”按钮。

history.go()(delta),用于在浏览器历史记录栈中进行前进或后退操作。


示例:

image-20250221092440529

基础

vue-router概述

目前前端流行的三大框架, 都有自己的路由实现:Angular的ngRouter,React的ReactRouter,Vue的vue-router

vue-router是基于路由和组件的:

  • 路由用于设定访问路径, 将路径和组件映射起来。
  • 在vue-router的单页面应用中, 页面的路径的改变就是组件的切换

安装

方式一:直接安装

sh
# 直接安装4.x版本的vue-router
npm install vue-router@4

方式二:使用create-vue创建Vue项目时选择安装

sh
# 1. 使用create-vue创建Vue项目
pnpm create vue
# 2. 在安装选项中选择安装vue-router

基本使用

步骤

  • 1、创建路由组件。
  • 2、配置路由映射: 组件和路径映射关系的routes数组。
  • 3、创建路由对象:通过createRouter()创建路由对象,并且传入routes和history模式。
  • 4、使用app.use()注册路由对象。
  • 5、使用路由:通过 <router-link><router-view>

实现

1、在router/index.js中创建并导出router实例

image-20221018223950786

2、在main.js中注册router实例到app上

image-20250221092625252

3、在app.vue使用<router-view>占位,并使用<router-link>导航到对应路由页面

image-20250221092650900

路由组件

<router-link>to replace? custom? active-class? exact-active-class? v-slot?,是 Vue Router 的导航组件,用于在SPA中生成可点击的路由链接,默认渲染为a标签。核心作用是实现无刷新页面切换,并自动处理路由激活状态。

<router-view>

<router-view>name?,v-slot?,,是 Vue Router 的核心组件,用于在SPA中渲染当前路由匹配的组件。它相当于一个动态占位符,根据路由规则切换显示内容。

路由重定向

createRouter()({history,routes,scrollBehavior?,...}),是 VueRouter4 中用于 创建路由实例 的核心函数。替代了 VueRouter3 的 new VueRouter()。

  • routesRouteRecordRaw[],定义路由配置的数组。路由对象 RouteRecordRaw 包含以下常见属性:
    • redirectstring|object,重定向目标。

示例:让路径默认跳到到首页, 并且渲染首页组件。

image-20250220180500936

路由懒加载

createRouter()({history,routes,scrollBehavior?,...}),是 VueRouter4 中用于 创建路由实例 的核心函数。替代了 VueRouter3 的 new VueRouter()。

  • routesRouteRecordRaw[],定义路由配置的数组。路由对象 RouteRecordRaw 包含以下常见属性:
    • componentComponent|()=>import(),对应组件或异步组件函数。

import()(modulePath),是 ES6 模块的动态导入语法,返回一个 Promise,允许在运行时异步加载模块。


当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就会更加高效。

Vue Router 支持开箱即用的动态导入,这意味着你可以用动态导入代替静态导入:

component可以传入一个组件,也可以接收一个函数,该函数需要返回一个Promise,而import函数就是返回一个Promise

image-20250221092926315


Webpack魔法注释

想把某个路由下的所有组件都打包在同个异步块 (chunk) 中。只需要使用命名 chunk,一个特殊的注释语法来提供 chunk name (需要 Webpack > 2.4):

image-20250221092952947

路由匹配规则

静态路径匹配

静态路径匹配:直接匹配固定 URL 结构,如 /home

ts
const routes = [
  { path: '/home', component: Home }, // 精确匹配 /home
  { path: '/about', component: About } // 精确匹配 /about
]

动态参数匹配

动态参数:通过 :param 捕获动态字段,参数值将解析到 $route.params

很多时候,我们需要将给定匹配模式的路由映射到同一个组件。例如,我们可能有一个 User 组件,它应该对所有用户进行渲染,但用户 ID 不同。在 Vue Router 中,我们可以在路径中使用一个动态字段来实现,我们称之为 路径参数

1、在router中的path字段添加一个路径参数:xxx

image-20250221093012630

2、在router-link标签的to中传入具体的参数值。

image-20221022203658800

3、在目标组件中通过$route.params.xxx访问路径参数。

image-20250221093030372


匹配多个参数:可以在同一个路由中设置有多个 路径参数,它们会映射到 $route.params 上的相应字段。

image-20250221093104128

image-20250221093126707

正则约束匹配

正则约束匹配

正则约束匹配:在动态参数后添加 (正则表达式) 限制参数格式。

ts
{ path: '/order/:id(\\d+)' } // 仅匹配数字 ID(如 /order/456)
{ path: '/file/:name(.*)' }  // 匹配任意字符串(含斜杠)
通配符匹配和NotFound

通配符匹配:pathMatch(.*) 匹配任意路径,常用于 404 页面。

ts
{ path: '/:pathMatch(.*)*', component: NotFound } // 末尾有*,表示解析匹配到的路由为对象

{ path: '/:pathMatch(.*)', component: NotFound } // 末尾没有*,表示不解析匹配到的路由,直接输出字符串

常规参数只匹配 url 片段之间的字符,用 / 分隔。如果我们想匹配任意路径,我们可以使用自定义的 路径参数 正则表达式,在 路径参数 后面的括号中加入 正则表达式 :

image-20250221093146364

通过 $route.params.pathMatch 获取到传入的参数

在这个特定的场景中,我们在括号之间使用了自定义正则表达式,并将pathMatch 参数标记为可选可重复*。这样做是为了让我们在需要的时候,可以通过将 path 拆分成一个数组,直接导航到路由:

image-20250221093207452

多参数匹配

可选参数

可选参数:通过 ? 标记参数为可选。

ts
{ path: '/blog/:page?' } // 匹配 /blog 或 /blog/2
重复参数

重复参数:通过 *+ 匹配多个路径段,结果以数组形式存储。

ts
{ path: '/sections/:chapters+' } // 匹配 /sections/a/b,chapters 为 ['a', 'b']

嵌套路由匹配

嵌套路由匹配:通过 children 定义嵌套结构,父组件需包含 <router-view>

ts
{
  path: '/dashboard',
  component: Dashboard,
  children: [
    { path: 'stats', component: Stats } // 匹配 /dashboard/stats
  ]
}

匹配模式控制

严格模式(strict):启用后路径末尾斜杠敏感(默认忽略)。

ts
{ path: '/user/', strict: true } // 仅匹配 /user/,不匹配 /user

大小写敏感(sensitive):路径区分大小写。

ts
{ path: '/Profile', sensitive: true } // 不匹配 /profile

别名

别名(alias):允许多路径映射同一组件,URL 不变化。

ts
{ path: '/home', alias: ['/', '/main'], component: Home }

重定向

重定向(redirect):路径跳转到新地址,URL 更新。

ts
{ path: '/old', redirect: '/new' }

匹配优先级

  • 静态路径优先:精确匹配的静态路由 > 动态路由 > 通配符路由。
  • 参数顺序影响:相同层级的动态路由按配置顺序匹配,先定义者优先。

获取路径参数

组件中获取路径参数的方式

方式一:模板中: $route.params.id

方式二:选项式API中: this.$route.params.id

方式三:组合式API中: useRoute().params.id

嵌套路由

基本使用

js
path: '/home'
children:
	path: '', name:'recommend', redirect:'/home/recommend'
	path: '/home', redirect:'/home/recommend'

	path: '/home/recommend'
	path: 'recommend'

1、路由映射: 在router的路由映射中定义children

image-20250221093229754

2、在根组件App.vue中使用<router-view>占位。

image-20250221093248857

2、在子组件User.vue中使用<router-view>占位。

image-20250221093304151

嵌套路由配置

children属性:在父路由配置中通过 children 数组定义子路由,子路由的 path 支持两种形式。

ts
const routes = [
  {
    path: '/parent',
    component: ParentComponent,
    children: [
      // 1. 相对路径:继承父路径,完整路径为 /parent/child
      { path: 'child', component: ChildComponent },
        
      // 2. 绝对路径:独立于父路径,完整路径为 /child
      { path: '/child', component: ChildComponent }
    ]
  }
]

动态参数继承:若父路由包含动态参数如 :id,子路由可通过 $route.params 直接访问。

ts
{
  path: '/user/:id',
  component: UserLayout,
  children: [
    // 子路由路径自动继承父级参数,完整路径为 /user/123/profile
    { path: 'profile', component: UserProfile }
  ]
}

组件模板占位

父组件中定义<router-view>:子路由的渲染位置由父组件模板中的 <router-view> 标签决定。若未定义该标签,子路由组件不会显示。

html
<!-- ParentComponent.vue -->
<template>
  <div>
    <h2>父级布局</h2>
    <router-view></router-view> <!-- 子路由在此渲染 -->
  </div>
</template>

默认子路由

默认子路由:设置 path: '' 作为默认子路由,当父路径被访问时自动加载。

ts
children: [
  { path: '', component: DefaultChild },
  { path: 'other', component: OtherChild }
]

注意:当使用''时,需要添加一个name属性,否则会提示警告。

image-20250221093343796


当你访问 /user/eduardo 时,在 Userrouter-view 里面什么都不会呈现,因为没有匹配到嵌套路由。也许你确实想在那里渲染一些东西。在这种情况下,你可以提供一个空的嵌套路径

image-20250221093329145

路由懒加载

路由懒加载:结合动态导入提升性能。

ts
children: [
  { path: 'stats', component: () => import('./UserStats.vue') }
]

结合UI库

结合UI库:在 Element Plus中通过菜单组件的router属性动态激活路由。

html
<el-menu :default-active="$route.path" router>
  <el-menu-item index="/user/detail">详情</el-menu-item>
  <el-menu-item index="/user/settings">设置</el-menu-item>
</el-menu>

命名父路由

命名父路由:通过push({name: 'user-parent'})父路由name导航时只会导航到父路由而不导航到嵌套子路由。

注意: 重新加载页面将始终显示嵌套的子路由,因为它被视为指向路径/users/:id 的导航,而不是命名路由。

image-20250221093356045

编程式导航

router.push()

router.push()(to),核心导航方法,用于 编程式导航到新路由,支持多种参数形式。


调用:在 Vue 实例中,你可以通过 $router 访问路由实例。因此你可以调用 this.$router.push()

router.push():会向 history 栈添加一个新的记录,当用户点击浏览器后退按钮时,会回到之前的 URL。

image-20250221093411892

path 与 params 的冲突:如果提供了 pathparams 会被忽略,上述例子中的 query 并不属于这种情况。

image-20250221093427774

router-link内部实现

  • 当你点击 <router-link> 时,内部会调用这个方法。

  • 由于属性 torouter.push() 接受的对象种类相同,所以两者的规则完全相同。

返回值router.push() 和所有其他导航方法都会返回一个 Promise,让我们可以等到导航完成后才知道是成功还是失败。

router.replace()

router.replace()(to),编程式导航方法,用于 替换当前浏览器历史记录中的路由,不会新增历史条目。适用于需要隐藏当前导航记录的场景,如登录后跳转,不希望用户通过返回按钮回到登录页。


对比push():它的作用类似于 router.push(),唯一不同的是,它在导航时不会向 history 添加新记录,它取代了当前的条目。

image-20250221093442596

router.go()

router.go()(n),全局导航方法,用于在 浏览器历史记录栈 中前进或后退指定的步数。行为类似于浏览器的前进/后退按钮。


该方法采用一个整数作为参数,表示在历史堆栈中前进或后退多少步,类似于 window.history.go(n)

image-20250221093459236

动态路由

动态添加路由

router.addRoute()(parentName?,route),是 Vue Router 提供的动态路由管理方法,允许在运行时向路由器实例添加新的路由规则。适用于需要根据用户权限、功能模块懒加载等场景动态扩展路由表的情况。


对路由的添加通常是通过 routes 选项来完成的,但是在某些情况下,你可能想在应用程序已经运行的时候添加路由

应用场景:根据用户不同的权限,注册不同的路由

语法

js
// 动态添加一个【路由】
$router.addRoute(路由对象)

// 动态添加一个【子路由】
$router.addRoute('父路由name', 子路由对象)

示例

动态添加一个【路由】

image-20250221093526394

动态添加一个【子路由】

image-20250221093559812

动态删除路由

router.removeRoute()(name),是 Vue Router 提供的动态路由管理方法,用于在运行时通过路由名称或addRoute()返回的移除函数来删除路由。已注册的路由规则。适用于需要根据用户权限、模块卸载等场景动态调整路由表的场景。


三种删除方式

  • 1、添加一个name相同的路由
  • 2、通过removeRoute方法,传入路由的名称
  • 3、通过addRoute方法的返回值回调

示例

1、添加一个name相同的路由

image-20221022220128117

2、通过removeRoute方法,传入路由的名称

image-20221022220204984

3、通过addRoute方法的返回值回调

image-20250221093619407

导航守卫

router.beforeEach()(guard)全局前置导航守卫,用于在每次路由跳转前执行自定义逻辑,如权限校验、数据预加载等。

router.afterEach()(guard)全局后置守卫,用于注册一个在 导航完成之后 执行的钩子函数。它不会改变导航结果,常用于执行与导航结果无关的后续处理操作,如埋点统计、页面标题更新等。

router.beforeResolve()()全局解析守卫,用于注册一个在 导航被确认之前 执行的钩子函数。


语法

image-20250221093637511

参数

  • to:即将要进入的路由目标对象
  • from:当前导航正要离开的路由对象
  • next:在Vue2中我们是通过next函数来决定如何进行跳转的【Vue3不再推荐】

返回值

  • false:取消当前导航
  • undefined | 不返回:进行默认导航
  • 一个路由地址:String | Object。跳转到该路由地址

注意:Vue3中利用返回值取代了Vue2中next的作用

示例

image-20250221093659414